package battleroom;

import com.jme3.app.state.AbstractAppState;
import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.PhysicsTickListener;
import com.jme3.bullet.collision.PhysicsCollisionObject;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.GhostControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Plane;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.LightControl;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Line;
import com.jme3.scene.shape.Sphere;
import java.util.Iterator;
import jme3tools.optimize.GeometryBatchFactory;
/**
 *
 * @author Adam
 */
public class PlayerState extends AbstractAppState
    implements PhysicsTickListener  {
    public  static final float PlayerWidth     = 1.5f;
    public  static final float PlayerHeight    = 4f;
    public static final float maxSpeed       = 100f;
    public static final float minSpeed       = 30f;
    public static final float walkSpeed      = 20f;
    public static final boolean debug = true;
    
    static float getMaxSpeed() {
        return maxSpeed;
    }
    
    private Node        playerRoot  = new Node("playerRoot");   //This will contains the player ghost and rigid body (for collision detection) as well as th player weapon model.
    private Spatial     playerSpat;
    private PlayerGhost         playerGhost;  
    private PlayerBody playerBody;
    public Plane playerPlane;
    protected Main app;
    private Vector3f moveTo = null;
    private float jumpForce = 0;
    private float jumpListenCount = 0;
    private float jumpListenDelay = .2f;    
    private BaseGun playerGun;
    SpotLight spot;
    
    public boolean tmpINITFORCE = true;
    
    private boolean doJump = false;
    
    public static float clampSpeed(float speed)
    {
        if(speed < PlayerState.minSpeed)
        {
            speed = PlayerState.minSpeed;
        }

        if(speed > PlayerState.maxSpeed)
        {
            speed = PlayerState.maxSpeed;
        }
        
        return speed;
    }
    
    private StarControl attachedTo;
    private Vector3f relativePosition;
    private Vector3f starNormal;
    private Vector3f starFaceCenter;
    private Vector3f jumpVector;
    
    private Vector3f closeTo[]; //An array of the axes the player is close to
    
    private Spatial swapFaceArrow;
    
    PlayerState(Main app)
    {
        this.app = app;
        SphereCollisionShape ghostShape = new SphereCollisionShape(PlayerHeight*5);        
        SphereCollisionShape bodyShape = new SphereCollisionShape(PlayerHeight);
        
        
        playerRoot.setLocalTranslation(new Vector3f(2f, 2f, 2f));
        
        playerGhost = new PlayerGhost(ghostShape, this);
        playerGhost.attachToWorld(playerRoot, this.app.bulletAppState.getPhysicsSpace());
        
        playerBody = new PlayerBody(bodyShape, this);
        playerRoot.addControl(playerBody);        
        app.bulletAppState.getPhysicsSpace().add(playerBody);
        app.bulletAppState.getPhysicsSpace().addCollisionListener(playerBody);
        app.bulletAppState.getPhysicsSpace().addTickListener(playerBody);
        
        InputManager inputManager = app.getInputManager();        
        inputManager.addMapping("key_space", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addListener(actionListener, new String[]{"key_space"});        
        inputManager.addListener(analogListener, new String[]{"key_space"});
        inputManager.addMapping("cam", new KeyTrigger(KeyInput.KEY_T));
        inputManager.addListener(actionListener, new String[]{"cam"});
        inputManager.addMapping("use", new KeyTrigger(KeyInput.KEY_E));
        inputManager.addListener(actionListener, new String[]{"use"});
        inputManager.addMapping("test", new KeyTrigger(KeyInput.KEY_R));
        inputManager.addListener(actionListener, new String[]{"test"});
        inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_Q));
        inputManager.addListener(actionListener, new String[]{"stop"});
        inputManager.addMapping("fire", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addListener(actionListener, "fire");
        inputManager.addMapping("w", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addListener(analogListener, new String[]{"w"});
        inputManager.addMapping("a", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addListener(analogListener, new String[]{"a"});
        inputManager.addMapping("s", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addListener(analogListener, new String[]{"s"});
        inputManager.addMapping("d", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addListener(analogListener, new String[]{"d"});
        inputManager.addMapping("mouse_move", new MouseAxisTrigger(MouseInput.AXIS_X, true),
                                              new MouseAxisTrigger(MouseInput.AXIS_X, false),
                                              new MouseAxisTrigger(MouseInput.AXIS_Y, true),
                                              new MouseAxisTrigger(MouseInput.AXIS_Y, false));
        inputManager.addListener(analogListener, "mouse_move");
        
        closeTo = new Vector3f[2];
        
        app.bulletAppState.getPhysicsSpace().addTickListener(this);
        
        if(debug)
        {
            Sphere point = new Sphere(8, 8, .2f);
            Geometry ptGeom = new Geometry("player", point);
            ptGeom.setMaterial(app.defaultMatRed);       
            playerRoot.attachChild(ptGeom);
        }
        
        PointLight testLight = new PointLight();
        testLight.setRadius(PlayerHeight*45);
        testLight.setColor(new ColorRGBA(.6f, .6f, 1f, 1f));
        app.getRootNode().addLight(testLight);
        LightControl playerLight = new LightControl(testLight);
        playerRoot.addControl(playerLight);
        
        spot = new SpotLight();
        spot.setSpotRange(100f);                           // distance
        spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam)
        spot.setSpotOuterAngle(35f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light)
        spot.setColor(ColorRGBA.White.mult(1.3f));         // light color
        spot.setPosition(app.getCamera().getLocation());               // shine from camera loc
        spot.setDirection(app.getCamera().getDirection());             // shine forward from camera loc
        playerRoot.addLight(spot);        
        
        app.getRootNode().attachChild(playerRoot);
        
        
    }
    private void addCloseToAxis(Vector3f axis)
    {
        if(closeTo[0] == null)
        {
            closeTo[0] = axis;
        }else if(closeTo[1] == null)
        {
            closeTo[1] = axis;
        }
    }
    
    private void removeCloseToAxis(Vector3f axis)
    {
        System.out.println("Remove axis");
        if(closeTo[0].equals(axis))
        {
            closeTo[0] = null;
            
            if(closeTo[1] != null)
            {
                closeTo[0] = closeTo[1].clone();
                closeTo[1] = null;
            }
        }else if(closeTo[1].equals(axis))
        {
            closeTo[1] = null;
        }
    }
    
    //This function clamps movement so the player can't move off the fac eof a star.
    //This also calculates the closeTo axese to allow for face to face movement
    private Vector3f safeMove(Vector3f test, Vector3f orig)
    {
        Vector3f axis = StarControl.excludeParallelComponent(starNormal, Vector3f.UNIT_XYZ.clone());
        Vector3f safeMove = test;
        
        if(axis.getX() == 1 && axis.getY() == 1)
        {
            //Clamp values
            if(Math.abs(test.getX()) > attachedTo.size())
            {
                safeMove.setX(orig.getX());
            }
            
            
            //Clamp Values
            if(Math.abs(test.getY()) > attachedTo.size())
            {
                safeMove.setY(orig.getY());
            }
        }else if(axis.getX() == 1 && axis.getZ() == 1)
        {
            //Clamp values
            if(Math.abs(test.getX()) > attachedTo.size())
            {
                safeMove.setX(orig.getX());
            }
            //Clamp values
            if(Math.abs(test.getZ()) > attachedTo.size())
            {
                safeMove.setZ(orig.getZ());
            }
            
        }else if(axis.getY() == 1 && axis.getZ() == 1)
        {
            //Clamp
            if(Math.abs(test.getY()) > attachedTo.size())
            {
                safeMove.setY(orig.getY());
            }
            
            //Clamp
            if(Math.abs(test.getZ()) > attachedTo.size())
            {
                safeMove.setZ(orig.getZ());
            }
        }
        updateCloseFaces();
        
        return safeMove;
    }
    
    private Vector3f closeFace;
    private void checkCloseToFace()
    {
        Vector3f close = null;
        if(closeTo[0] != null)
        {
            if(closeTo[1] != null)
            {
                float dist0 = closeTo[0].distance(app.getCamera().getDirection());
                float dist1 = closeTo[1].distance(app.getCamera().getDirection());
                
                if(dist0 > dist1)
                {
                    close = closeTo[1].clone();
                }else{
                    close = closeTo[0].clone();
                }
            }else{
                close = closeTo[0].clone();
            }
        }
        
        closeFace = close;
    }
    
    private void clearCloseFaces(){
        closeTo[0] = null;
        closeTo[1] = null;
        closeFace = null;
    }
    
    private void updateCloseFaces(){
        Vector3f axis = StarControl.excludeParallelComponent(starNormal, Vector3f.UNIT_XYZ.clone());
        
        if(axis.getX() == 1 && axis.getY() == 1)
        {
            //Check for axis closeness
            if(Math.abs(relativePosition.getX()) >= attachedTo.size() - PlayerWidth)
            {
                if(relativePosition.getX() < 0)
                {
                    addCloseToAxis(Vector3f.UNIT_X.clone().mult(-1));
                }else{
                    addCloseToAxis(Vector3f.UNIT_X.clone());
                }
            }else{
                if(closeToHasAxis(Vector3f.UNIT_X.clone()))
                {
                    removeCloseToAxis(Vector3f.UNIT_X.clone());
                }
            }
            
            //Check for axis closeness
            if(Math.abs(relativePosition.getY()) >= attachedTo.size() - PlayerWidth)
            {
                if(relativePosition.getY() < 0)
                {
                    addCloseToAxis(Vector3f.UNIT_Y.clone().mult(-1));
                }else{
                    addCloseToAxis(Vector3f.UNIT_Y.clone());
                }
            }else{
                if(closeToHasAxis(Vector3f.UNIT_Y.clone()))
                {
                    removeCloseToAxis(Vector3f.UNIT_Y.clone());
                }
            }
        }else if(axis.getX() == 1 && axis.getZ() == 1)
        {
            
            //Check for axis closeness
            if(Math.abs(relativePosition.getX()) >= attachedTo.size() - PlayerWidth)
            {
                if(relativePosition.getX() < 0)
                {
                    addCloseToAxis(Vector3f.UNIT_X.clone().mult(-1));
                }else{
                    addCloseToAxis(Vector3f.UNIT_X.clone());
                }
            }else{
                if(closeToHasAxis(Vector3f.UNIT_X.clone()))
                {
                    removeCloseToAxis(Vector3f.UNIT_X.clone());
                }
            }
            //Check for axis closeness
            if(Math.abs(relativePosition.getZ()) >= attachedTo.size() - PlayerWidth)
            {
                if(relativePosition.getZ() < 0)
                {
                    addCloseToAxis(Vector3f.UNIT_Z.clone().mult(-1));
                }else{
                    addCloseToAxis(Vector3f.UNIT_Z.clone());
                }
            }else{
                if(closeToHasAxis(Vector3f.UNIT_Z.clone()))
                {
                    removeCloseToAxis(Vector3f.UNIT_Z.clone());
                }
            }
        }else if(axis.getY() == 1 && axis.getZ() == 1)
        {
            
            //Check for axis closeness
            if(Math.abs(relativePosition.getY()) >= attachedTo.size() - PlayerWidth)
            {
                if(relativePosition.getY() < 0)
                {
                    addCloseToAxis(Vector3f.UNIT_Y.clone().mult(-1));
                }else{
                    addCloseToAxis(Vector3f.UNIT_Y.clone());
                }
            }else{
                if(closeToHasAxis(Vector3f.UNIT_Y.clone()))
                {
                    removeCloseToAxis(Vector3f.UNIT_Y.clone());
                }
            }
            
            //Check for axis closeness
            if(Math.abs(relativePosition.getZ()) >= attachedTo.size() - PlayerWidth)
            {
                if(relativePosition.getZ() < 0)
                {
                    addCloseToAxis(Vector3f.UNIT_Z.clone().mult(-1));
                }else{
                    addCloseToAxis(Vector3f.UNIT_Z.clone());
                }
            }else{
                if(closeToHasAxis(Vector3f.UNIT_Z.clone()))
                {
                    removeCloseToAxis(Vector3f.UNIT_Z.clone());
                }
            }
        }
    }
    
    private boolean closeToHasAxis(Vector3f check)
    {
        if(closeTo[0] != null)
        {
            if(closeTo[0].equals(check)){
                return true;
            }
        }
        
        if(closeTo[1] != null)
        {
            if(closeTo[1].equals(check)){
                return true;
            }
        }
        
        return false;
    }
    
    private Geometry prevSelection = null;
    
    private boolean calcHighlightFromMove = false;
    private boolean calcHighlightFromMouse = false;
    private AnalogListener analogListener = new AnalogListener(){
        public void onAnalog(String name, float value, float tpf)
        {
            if(name.equals("mouse_move"))
            {
                calcHighlightFromMouse=true;
            }
            
            if(name.equals("w"))
            {                
                if(isAttached() && moveTo == null)
                {                    
                    Vector3f move = app.getCamera().getDirection().mult(walkSpeed*tpf);  
                    StarControl.excludeParallelComponent(starNormal, move);
                    relativePosition = safeMove(relativePosition.add(move), relativePosition);
                }
            }
            
            if(name.equals("s"))
            {                
                if(isAttached() && moveTo == null)
                {                    
                    Vector3f move = app.getCamera().getDirection().mult(walkSpeed*tpf);
                    StarControl.excludeParallelComponent(starNormal, move);
                    move.multLocal(-1);
                    relativePosition = safeMove(relativePosition.add(move), relativePosition);
                }
            }
            
            if(name.equals("a"))
            {                
                if(isAttached() && moveTo == null)
                {                    
                    Vector3f move = app.getCamera().getDirection().cross(app.getCamera().getUp()).mult(walkSpeed*tpf);
                    StarControl.excludeParallelComponent(starNormal, move);
                    move.multLocal(-1);
                    relativePosition = safeMove(relativePosition.add(move), relativePosition);
                }
            }
            
            if(name.equals("d"))
            {                
                if(isAttached() && moveTo == null)
                {                    
                    Vector3f move = app.getCamera().getDirection().cross(app.getCamera().getUp()).mult(walkSpeed*tpf);
                    StarControl.excludeParallelComponent(starNormal, move);
                    relativePosition = safeMove(relativePosition.add(move), relativePosition);
                }
            }
            
            if(name.equals("key_space"))
            {
                if(isAttached() && moveTo == null && jumpListenCount >= jumpListenDelay)
                {
                    if(jumpForce<maxSpeed){
                        jumpForce += value*maxSpeed;
                    }else if(jumpForce > maxSpeed){
                        jumpForce = maxSpeed;
                    }
                    
                    app.getHud().updateJumpForceIndicator(jumpForce/maxSpeed);
                    
                    if(!app.getHud().getJumpForceIndicatorShowing())
                    {
                        app.getHud().toggleJumpForceIndicator(true);
                    }
                }else if(jumpListenCount < jumpListenDelay){
                    jumpListenCount += value;
                }
            }
        }
    };
    
    private ActionListener actionListener = new ActionListener() {
        public void onAction(String name, boolean keyPressed, float tpf) {
          if (name.equals("key_space") && !keyPressed) {
              if(tmpINITFORCE)
              {
                  doJump = true;
                  jumpVector = app.getCamera().getDirection().mult(maxSpeed);
                  tmpINITFORCE = false;
              } 
              
              
              if(playerGhost.isColliding())
              {
                  if(isAttached())
                  {
                      if(jumpForce < minSpeed)
                      {
                          jumpForce = minSpeed;
                      }
                      
                      jumpVector = app.getCamera().getDirection().mult(jumpForce);                      
                      doJump = true;
                      jumpForce = 0;
                      jumpListenCount = 0;
                      
                      app.getHud().toggleJumpForceIndicator(false);
                  }
              }
          }
          
          if(name.equals("use") && !keyPressed)
          {
              if(isAttached())
              {
                  if(closeFace != null)
                  {
                      swapFaceWithCloseFace();
                  }
              }else{
                  StarControl closest = playerGhost.getClosestStar();
                  if(!playerBody.hasCollidedWith(closest))
                  {
                    attachToStar(closest);
                  }                  
              }
          }
          
          if (name.equals("cam") && !keyPressed) {                       
            app.camFollow = (app.camFollow) ? false : true;
          }
          
          if(name.equals("test") & !keyPressed)
          {              
            test();
          }
          
          if (name.equals("stop") && !keyPressed) {
            playerBody.setLinearVelocity(Vector3f.ZERO);
          }          
        }        
    };
    public void attachToStar(StarControl star)
    {
        if(attachedTo != null) return ;
        if(star == null) return;
        
        attachedTo = star;
        moveToSurface();
    }
    
    public boolean isAttached() {
        return !(attachedTo == null);
    }
    
    @Override
    public void update(float tpf)
    {
        if(doJump && isAttached())
        {
            detachFromStar();
        }
        
        Vector3f previousLocation = playerRoot.getLocalTranslation();
        
        if(isAttached())
        {           
            if(moveTo != null)
            {
                Vector3f current    = playerRoot.getLocalTranslation().clone();
                Vector3f next       = current.interpolate(moveTo, 10*tpf);            
                playerRoot.setLocalTranslation(next);
                playerBody.setPhysicsLocation(next);
                if(isCloseTo(next, moveTo, 10*tpf))
                {
                    playerRoot.setLocalTranslation(moveTo);
                    moveTo = null;
                }            
            }else{                
                playerRoot.setLocalTranslation(starFaceCenter.add(relativePosition));
            }
            
            playerBody.setPhysicsLocation(playerRoot.getLocalTranslation());  
            
            checkCloseToFace();
        }else{
            getRootNode().setLocalTranslation(playerBody.getPhysicsLocation());            
        }   
        
        
        spot.setPosition(app.getCamera().getLocation());               // shine from camera loc
        spot.setDirection(app.getCamera().getDirection());             // shine forward from camera loc
    }
    
    public void test()
    {        
        tmpINITFORCE = true;
    }
    
    public PlayerBody getBody()
    {
        return playerBody;
    }

    Node getRootNode() {
        return playerRoot;
    }
    GhostControl getGhost()
    {
        return playerGhost;
    }
    
    private int numberOfRays() {
        return numberOfRays();
    }

    public void prePhysicsTick(PhysicsSpace space, float f) {    
        playerBody.setAngularVelocity(Vector3f.ZERO);
        
        if(isAttached())
        {
            playerBody.setLinearVelocity(Vector3f.ZERO);
        }
        
        if(doJump)
        {
            playerBody.setLinearVelocity(jumpVector);
            doJump = false;
        }  
    }

    public void physicsTick(PhysicsSpace space, float f) {  
    }
    
    public Vector3f getLinearVelocity()
    {
        return playerBody.getLinearVelocity();
    }
    
    Vector3f getAxisClosestToMovement()
    {
        Vector3f movement = playerBody.getLinearVelocity().normalize();
        float distX = movement.distance(Vector3f.UNIT_X);
        float distY = movement.distance(Vector3f.UNIT_Y);
        float distZ = movement.distance(Vector3f.UNIT_Z);
        
        if(distX < distY){
            if(distX < distZ)
                return Vector3f.UNIT_X;            
        }else if(distY < distZ){
            return Vector3f.UNIT_Y;
        }
        
        return Vector3f.UNIT_Z;
    }
    
    Vector3f getAxisOfGreatestMovement()
    {
        Vector3f movement = getLinearVelocity();
        float distX = movement.getX();
        float distY = movement.getY();
        float distZ = movement.getZ();
        
        if(distX < distY){
            if(distX < distZ)
                return Vector3f.UNIT_X;            
        }else if(distY < distZ){
            return Vector3f.UNIT_Y;
        }
        
        return Vector3f.UNIT_Z;
    }
    
    
    //Gets the axis the normalized component of vect is closest to f
    // f = 1, vect.x = .999 vect.y = .8 vect.z = .998 returns x axis
    Vector3f getAxisClosestTo(float f, Vector3f vect) {
        float distX = Math.abs(vect.getX());
        float distY = Math.abs(vect.getY());
        float distZ = Math.abs(vect.getZ());
        
        distX = f - distX;
        distY = f - distY;
        distZ = f - distZ;
        
        if(distX < distY){
            if(distX < distZ)
                return Vector3f.UNIT_X;            
        }else if(distY < distZ){
            return Vector3f.UNIT_Y;
        }
        
        return Vector3f.UNIT_Z;
    }
    
    public void swapFaceWithCloseFace()
    {
        if(!isAttached()) return;
        
        Vector3f wantedPos = starNormal.mult(attachedTo.size() - PlayerWidth);
        starNormal = closeFace;        
        float offset = calculateStarOffset(); 
        clearCloseFaces();
        
        starFaceCenter = attachedTo.getFaceCenter(starNormal).add(starNormal.mult(offset));     
        relativePosition = wantedPos;
        moveTo = starFaceCenter.add(relativePosition);
    }
    
    public void moveToSurface()
    {
        if(!isAttached()) return;
        
        Vector3f position = playerRoot.getLocalTranslation();
        //Get the direction the star is relative to the player
        Vector3f dir = getAttached().getSpatial().getLocalTranslation().subtract(position).normalize();
        //Cast a ray into the star to find it's surface
        Ray sRay = new Ray(position, dir);
        CollisionResults results = new CollisionResults();
        getAttached().getSpatial().collideWith(sRay, results);
        CollisionResult result = results.getClosestCollision();
        
         //Make sure we are on a face not a corner
        Vector3f test = Vector3f.UNIT_XYZ.clone();
        StarControl.excludeParallelComponent(result.getContactNormal(), test);
        Vector3f normal = result.getContactNormal();
        if(test.equals(Vector3f.UNIT_XYZ))
        {
            //Approximate face normal
            Vector3f axis = getClosest(normal, 1f, .25f);
            normal.multLocal(axis);
        }
        
        starNormal = normal;
        
        moveTo = result.getContactPoint();
        dir.multLocal(-1);
        
        float offset = calculateStarOffset();        
        starFaceCenter = attachedTo.getFaceCenter(starNormal).add(starNormal.mult(offset));        
        moveTo = moveTo.add(normal.mult(offset));        
        relativePosition = moveTo.subtract(starFaceCenter);
        StarControl.excludeParallelComponent(starNormal.clone(), relativePosition);   
    }
    
    private float calculateStarOffset()
    {
        float offset = 0; //Amount to offset the player from the star so that the camera is not on the surface of the star
        //Add Player height if on y axis, add width if on xz axis
        
            System.out.println("Is you on top or bot? " + starNormal);
        if(Math.abs(starNormal.getX()) == 1 || Math.abs(starNormal.getZ()) == 1)
        {
            offset = PlayerHeight;
        }else{
            System.out.println("YOU ARE ON TOP OR BOTTOM");
            offset = PlayerHeight*2;
        }
        
        return offset;
    }
    
    //Don't really know where this should go either... maybe we need a utility class?
    //Returns true if val is within tolerance distance of closeTo
    public static boolean isCloseTo(float val, float closeTo, float tolerance)
    {
        float absCheck = Math.abs(closeTo) - Math.abs(val);
        
        if(absCheck <= tolerance)
        {
            return true;
        }
        
        return false;
    }
    
    public static boolean isCloseTo(Vector3f val, Vector3f closeTo, float tolerance)
    {
        if(isCloseTo(val.getX(), closeTo.getX(), tolerance) && isCloseTo(val.getY(), closeTo.getY(), tolerance) && isCloseTo(val.getZ(), closeTo.getZ(), tolerance))
        {
            return true;
        }
        
        return false;
    }
    
    //Returns axis of the component closest to close to
    public static Vector3f getClosest(Vector3f val, float closeTo, float tolerance)
    {
        float checkX = Math.abs(closeTo) - Math.abs(val.getX());
        float checkY = Math.abs(closeTo) - Math.abs(val.getY());
        float checkZ = Math.abs(closeTo) - Math.abs(val.getZ());
        
        if(checkX <= tolerance && checkX < checkY)
        {
            if(checkX < checkZ)
            {
                return new Vector3f(1, 0, 0);
            }else if(checkX == checkZ)
            {
                return new Vector3f(1, 0, 1);
            }
        }else if(checkX == checkY && checkY == checkZ && checkX <= tolerance){
            return new Vector3f(1, 1, 1);
        }else if(checkX == checkY && checkX <= tolerance){
            return new Vector3f(1, 1, 0);
        }else if(checkY <= tolerance && checkY < checkZ){
            return new Vector3f(0, 1, 0);
        }else if(checkY == checkZ && checkY <= tolerance){
            return new Vector3f(0, 1, 1);
        }else if(checkZ <= tolerance){
            return new Vector3f(0, 0, 1);
        }
        
        return new Vector3f(0, 0, 0);
    }

    private StarControl getAttached() {
        return attachedTo;
    }
    
    private void detachFromStar()
    {        
      attachedTo = null; 
      moveTo = null;
      relativePosition = null;
      starNormal = null;
      starFaceCenter = null;
      clearCloseFaces();
    }
    
}